package stendcontrol;

import java.util.ArrayList;
import services.ConvIntByte;

public class TransmitExp {
    //список слушателей передающего данные

    protected ArrayList<TransmitListener> tr_listeners = new 
            ArrayList<TransmitListener>();
    //флаг передачи false - не передавать листенерам
    protected boolean transmiting = false;
    protected int cnt_sens = Configurator.COUNT_SENSOR;
    protected final int MAX_CNT_FLT = 255;
    protected int[][] filter_buffer = new int[cnt_sens][MAX_CNT_FLT];
    protected long[] filter_sum = new long[cnt_sens];
    protected int cur_filter = 0;
    protected int filter_value = 0;
    protected boolean first_cycle = true;
    protected int buff = 0;

    /**
     * Operation добавить слушателя данных
     *
     * @param trl - слушатель
     * @return
     */
    public synchronized void addTransmitListener(TransmitListener trl) {
        tr_listeners.add(trl);
    }

    /**
     * Operation
     *
     * @param trl
     * @return
     */
    public synchronized void removeListener(TransmitListener trl) {
        tr_listeners.remove(trl);
    }

    /**
     * Operation
     *
     * @param numtrl
     * @return
     */
    public synchronized void removeListener(int numtrl) {
        tr_listeners.remove(numtrl);
    }

    public synchronized void removeAllListeners() {
        tr_listeners.clear();
    }

    private synchronized void clearFilter() {
        for (int j = 0; j < cnt_sens; j++) {
            filter_sum[j] = 0;
            for (int k = 0; k < MAX_CNT_FLT; k++) {
                filter_buffer[j][k] = 0;
            }
        }
        cur_filter = 0;
        first_cycle = true;
    }

    /**
     * Operation
     *
     * @return
     */
    public void startTransmitToExp() {
        clearFilter();
        transmiting = true;
    }

    /**
     * Operation
     *
     * @return
     */
    public void stopTransmitToExp() {
        transmiting = false;
    }
    //счетчик листенеров
    private int i = 0;

    /**
     * Трансляция буфера списку листенеров
     *
     * @param buf - передаваемый буфер
     * @param len - длина значещих байтов
     */
    public synchronized void translateToListeners(byte[] buf, int len) {
        i = tr_listeners.size();
        //фильтрация для скорости сделана только для 3-х датчиков
        if ((buf[0] & 0xF0) == 0x10 && filter_value != 0) {

            cur_filter++;
            if (cur_filter == filter_value) {
                cur_filter = 0;
                first_cycle = false;

                filter_buffer[0][cur_filter] = ((buf[1] + 256) % 256 << 8)
                        | ((buf[2] + 256) % 256);
                filter_buffer[1][cur_filter] = ((buf[3] + 256) % 256 << 8)
                        | ((buf[4] + 256) % 256);
                filter_buffer[2][cur_filter] = ((buf[5] + 256) % 256 << 8)
                        | ((buf[6] + 256) % 256);
                filter_buffer[0][filter_value] = filter_buffer[0][cur_filter];
                filter_buffer[1][filter_value] = filter_buffer[1][cur_filter];
                filter_buffer[2][filter_value] = filter_buffer[2][cur_filter];
            } else {
                filter_buffer[0][cur_filter] = ((buf[1] + 256) % 256 << 8)
                        | ((buf[2] + 256) % 256);
                filter_buffer[1][cur_filter] = ((buf[3] + 256) % 256 << 8)
                        | ((buf[4] + 256) % 256);
                filter_buffer[2][cur_filter] = ((buf[5] + 256) % 256 << 8)
                        | ((buf[6] + 256) % 256);
            }
            filter_sum[0] += filter_buffer[0][cur_filter];
            filter_sum[1] += filter_buffer[1][cur_filter];
            filter_sum[2] += filter_buffer[2][cur_filter];
            filter_sum[0] -= filter_buffer[0][cur_filter + 1];
            filter_sum[1] -= filter_buffer[1][cur_filter + 1];
            filter_sum[2] -= filter_buffer[2][cur_filter + 1];

            if (first_cycle) {
                buff = (int) (filter_sum[0] / (cur_filter));
                buf[1] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[2] = ConvIntByte.int2Byte(buff & 0xff);
                buff = (int) (filter_sum[1] / (cur_filter));
                buf[3] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[4] = ConvIntByte.int2Byte(buff & 0xff);
                buff = (int) (filter_sum[2] / (cur_filter));
                buf[5] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[6] = ConvIntByte.int2Byte(buff & 0xff);
            } else {
                buff = (int) (filter_sum[0] / (filter_value-1));
                buf[1] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[2] = ConvIntByte.int2Byte(buff & 0xff);
                buff = (int) (filter_sum[1] / (filter_value-1));
                buf[3] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[4] = ConvIntByte.int2Byte(buff & 0xff);
                buff = (int) (filter_sum[2] / (filter_value-1));
                buf[5] = ConvIntByte.int2Byte((buff >> 8) & 0xff);
                buf[6] = ConvIntByte.int2Byte(buff & 0xff);
            }
        }
        while (i-- != 0) {
            tr_listeners.get(i).transmitPerformed(buf, len);
        }
    }

    public void setFilterValue(int filter_value) {
        if (filter_value >= 0 && filter_value < MAX_CNT_FLT) {
            clearFilter();
            this.filter_value = filter_value;
        } else {
            StendLogger.log(StendLogger.MSG_ERROR, "Bad filter value. "
                    + "Range of filter value: 0.." + MAX_CNT_FLT + ". Current "
                    + "value: " + filter_value);
        }
    }
}
